﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;
using System.Reflection;

namespace BrainTechLLC
{
#if !NO_SILVERLIGHT

    public class PropertyDescriptorCollection : ThreadSafeLookup<string, PropertyInfo>
    {
        public PropertyDescriptorCollection(PropertyInfo[] pds)
        {
            foreach (var pd in pds)
            {
                Add(pd.Name, pd);
            }
        }
    }

#endif

    public static class ShallowCopyTypeExtensions
    {
        private static readonly ThreadSafeLookupOnDemandWithDelegate<Type, PropertyDescriptorCollection> _allProperties = new ThreadSafeLookupOnDemandWithDelegate<Type, PropertyDescriptorCollection>();

#if NO_SILVERLIGHT
        public static object GetValue(this PropertyDescriptor pd, object obj, object extraParam)
        {
            return pd.GetValue(obj);
        }
#endif

        public static ThreadSafeLookupOnDemandWithDelegate<Type, PropertyDescriptorCollection> AllProperties
        {
            get { return _allProperties; }
        }

        public static object Copy(this object original)
        {
            Type t = original.GetType();
            object copy = TypeProvider.GetInstance().CreateInstanceFromType(t);
#if NO_SILVERLIGHT
            PropertiesForType(t, false).ForEach<PropertyDescriptor>(propInfo => propInfo.SetValue(copy, propInfo.GetValue(original)));
#else
            PropertiesForType(t, false).ForEach<PropertyInfo>(propInfo => propInfo.SetValue(copy, propInfo.GetValue(original, null), null));
#endif
            return copy;
        }

        public static PropertyDescriptorCollection PropertiesForType(this Type t, bool includeReadOnly)
        {
            return AllProperties.Get(t, delegate(Type type)
            {
#if NO_SILVERLIGHT
                List<PropertyDescriptor> propInfoList = TypeDescriptor.GetProperties(t).Take<PropertyDescriptor>(pd => includeReadOnly || !pd.IsReadOnly);
#else
                List<PropertyInfo> propInfoList = t.GetProperties().Take<PropertyInfo>(pd => includeReadOnly || pd.CanWrite);
#endif
                var pdc = new PropertyDescriptorCollection(propInfoList.ToArray());
                return pdc;
            });
        }

        public static T QuickCopy<T>(T original) where T : class, IQuickCopy, new()
        {
            return original.Copy() as T;
        }
    }
}